package net.alcuria.ball;

public class Ball {

	final int TILE_AIR = 0;
	final int TILE_GROUND = 1;
	final int TILE_SWITCH_A = 2;
	final int POWERUP_DEFAULT = 3;
	final int POWERUP_FEATHER = 4;
	final int POWERUP_HEAVY = 5;
	final int POWERUP_ICE = 6;
	final int POWERUP_FIRE = 7;
	final int TILE_CARROT = 10;
	final int TILE_SPRING = 15;
	final int TILE_BREAKABLE = 20;
	final int TILE_WATER = 120;
	final int TILE_ICE = 125;

	public int maxYVel = 12;
	public int fallTimer;
	public int jumpPower;
	public int powerup;
	public final int width;
	public int facing;
	public float x;
	public float y;
	public float xVel;
	public float yVel;
	public float g;
	public float bounceDecay;
	public float bounceThreshold;
	public float friction;

	public boolean onSurface = false;
	public boolean reflect = false;
	public boolean inWater = false;
	public boolean fireJump = false;
	public boolean breakSound = false;

	public int particleX = 0;
	public int particleY = 0;

	int xOffset = 0;

	Sprite character = new Sprite(Assets.character, 48, 48);
	Sprite ball = new Sprite(Assets.ball, 48, 48);

	public Ball(int x, int y){
		fallTimer = 0;
		width = 48;
		powerup = POWERUP_DEFAULT;
		this.x = x;
		this.y = y;
		xVel = 5;
		yVel = 0;
		bounceDecay = 0.2F;
		bounceThreshold = 7F;
		friction = 0.0F;

		g = 0.5F;
		jumpPower = 10;
	}

	public void jump(){
		if(powerup == POWERUP_FIRE && fireJump == false){
			xVel *= 2;
			fireJump = true;
		}
		yVel = -1 * jumpPower;
	}

	public void springJump(){
		yVel = -1 * 15;
	}

	public void update(float deltaTime, Director particleDirector){

		// update the sprite
		character.update(deltaTime);
		ball.update(deltaTime);

		// update position/velocity
		x = x + xVel;
		y = y + yVel;
		if(!onSurface){
			yVel = yVel + g;
			if (yVel > maxYVel){
				yVel = maxYVel;
			}
		}

		// ensure ball is within the boundaries of the map
		if (x > width && y > width && x + width < Assets.map.width*Assets.map.tileWidth && y + width < Assets.map.height*Assets.map.tileWidth) {

			// check collisions below
			if(Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] == TILE_AIR || Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] == TILE_CARROT){
				if(onSurface){
					onSurface = false;

				}
				fallTimer++;
			} else {
				fallTimer = 0;

				// push ball "back" so it is above the surface
				while(Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width-1)/32)] != TILE_AIR /* && y > 0 */){
					y--;
				}



				if (powerup == POWERUP_FIRE){
					breakSound = false;
					for(int i=-4; i<=width+4; i = i+4){
						if (Assets.map.lowerMap[(int) ((x+i/2)/32)][(int) ((y+width+2)/32)] == TILE_ICE){
							Assets.map.collisionMap[(int) ((x+i/2)/32)][(int) ((y+width+2)/32)] = 0;
							Assets.map.lowerMap[(int) ((x+i/2)/32)][(int) ((y+width+2)/32)] = 0;
							particleDirector.add(new Particle(32, 32, (int) ((x+i/2)/32)*32, (int) ((y+width+2)/32)*32, Particle.TYPE_ICEBREAK));

							if(!breakSound){
								Assets.hiss.play(1);
								breakSound = true;
							}
						}
					}
					
					// fireball powerup xVel reset hack
					if(fireJump && Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] != TILE_SPRING){
						xVel /= 2;
						fireJump = false;
					}
				}

				// set to ground
				if(!onSurface){
					onSurface = true;

					// do heavy powerup ground lander
					if (powerup == POWERUP_HEAVY){
						Assets.land.play(1);
						particleDirector.add(new Particle(75,20, (int)(x - 15 + 5 * xVel), (int)y + 28, Particle.TYPE_DUST));
						if(yVel > 1){
							breakSound = false;

							// check for a rock break
							for(int i=-4; i<=width+4; i = i+4){
								if (Assets.map.collisionMap[(int) ((x+i/2)/32)][(int) ((y+width+2)/32)] == TILE_BREAKABLE){
									Assets.map.collisionMap[(int) ((x+i/2)/32)][(int) ((y+width+2)/32)] = 0;
									Assets.map.lowerMap[(int) ((x+i/2)/32)][(int) ((y+width+2)/32)] = 0;
									Assets.map.upperMap[(int) ((x+i/2)/32)][(int) ((y+width+2)/32)] = 0;
									particleDirector.add(new Particle(32, 32, (int) ((x+i/2)/32)*32, (int) ((y+width+2)/32)*32, Particle.TYPE_BREAK));
									yVel = 0;
									if(!breakSound){
										Assets.breaks.play(1);
										breakSound = true;
									}
								}
							}

						}
					}
					yVel = 0;
				}
			}

			// check for any ice creation tiles
			if (powerup == POWERUP_ICE && Assets.map.lowerMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] != TILE_ICE && Assets.map.upperMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] >= TILE_WATER && Assets.map.upperMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] < TILE_WATER + 4){
				Assets.map.lowerMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] = TILE_ICE;
				Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] = TILE_GROUND;
				Assets.ice.play(1);
				while(Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width-1)/32)] != TILE_AIR /* && y > 0 */){
					y--;
				}
			}

			// check for spring collision
			if (Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] == TILE_SPRING){

				// initiate spring animation
				Assets.map.lowerMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)]++;
				Assets.map.lowerMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)-1]++;
				Assets.spring.play(1);				

				// do jump
				springJump();

			}

			// check for powerup collisions				
			if (powerup != POWERUP_DEFAULT && Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] == POWERUP_DEFAULT ) {
				setPowerup(POWERUP_DEFAULT);
				particleDirector.add(new Particle(77,77, (int)x - 16, (int)y - 16, Particle.TYPE_POWERUP));
				Assets.powerup.play(1);
			} else if (powerup != POWERUP_FEATHER && Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] == POWERUP_FEATHER ) {
				setPowerup(POWERUP_FEATHER);
				particleDirector.add(new Particle(77,77, (int)x - 16, (int)y - 16, Particle.TYPE_POWERUP));
				Assets.powerup.play(1);
			} else if (powerup != POWERUP_HEAVY && Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] == POWERUP_HEAVY) {
				setPowerup(POWERUP_HEAVY);
				particleDirector.add(new Particle(77,77, (int)x - 16, (int)y - 16, Particle.TYPE_POWERUP));
				Assets.powerup.play(1);
			} else if (powerup != POWERUP_ICE && Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] == POWERUP_ICE) {
				setPowerup(POWERUP_ICE);
				particleDirector.add(new Particle(77,77, (int)x - 16, (int)y - 16, Particle.TYPE_POWERUP));
				Assets.powerup.play(1);
			} else if (powerup != POWERUP_FIRE && Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) ((y+width)/32)] == POWERUP_FIRE) {
				setPowerup(POWERUP_FIRE);
				particleDirector.add(new Particle(77,77, (int)x - 16, (int)y - 16, Particle.TYPE_POWERUP));
				Assets.powerup.play(1);
			}

			// check for an above collision
			if (yVel < 0){
				if(Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) (y/32)] == TILE_GROUND){
					yVel=0;
					while((Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) (y/32)] == TILE_GROUND ) && y > 0){
						y++;
					}

				} else if (powerup == POWERUP_HEAVY && (Assets.map.collisionMap[(int) ((x+width/2-14)/32)][(int) (y/32)] == TILE_BREAKABLE || Assets.map.collisionMap[(int) ((x+width/2+14)/32)][(int) (y/32)] == TILE_BREAKABLE)){

					// check for a rock break
					if (Assets.map.collisionMap[(int) ((x+width/2-14)/32)][(int) (y/32)] == TILE_BREAKABLE){
						Assets.map.collisionMap[(int) ((x+width/2-14)/32)][(int) (y/32)] = 0;
						Assets.map.lowerMap[(int) ((x+width/2-14)/32)][(int) (y/32)] = 0;
						Assets.map.upperMap[(int) ((x+width/2-14)/32)][(int) (y/32)] = 0;
						particleDirector.add(new Particle(32, 32, (int) ((x+width/2-14)/32)*32, (int) ((y)/32)*32, Particle.TYPE_BREAK));
						if(!breakSound){
							Assets.breaks.play(1);
							breakSound = true;
						}
					}
					if (Assets.map.collisionMap[(int) ((x+width/2+14)/32)][(int) (y/32)] == TILE_BREAKABLE){
						Assets.map.collisionMap[(int) ((x+width/2+14)/32)][(int) (y/32)] = 0;
						Assets.map.lowerMap[(int) ((x+width/2+14)/32)][(int) (y/32)] = 0;
						Assets.map.upperMap[(int) ((x+width/2+14)/32)][(int) (y/32)] = 0;
						particleDirector.add(new Particle(32, 32, (int) ((x+width/2+14)/32)*32, (int) ((y)/32)*32, Particle.TYPE_BREAK));
						if(!breakSound){
							Assets.breaks.play(1);
							breakSound = true;
						}
					}
					y = y - yVel; // push back?
					yVel = 0;
				} else if (Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) (y/32)] == TILE_SPRING){
					yVel=0;
					while((Assets.map.collisionMap[(int) ((x+width/2)/32)][(int) (y/32)] == TILE_SPRING ) && y > 0){
						y++;
					}
				}
			}

			// check for a collision to LEFT/RIGHT of ball
			xOffset = xVel < 0 ? 0 : width;
			
			if(Assets.map.collisionMap[(int) ((x+xOffset)/32)][(int) ((y+width-8)/32)] != TILE_AIR){

				if (Assets.map.collisionMap[(int) ((x+xOffset)/32)][(int) ((y+width-8)/32)] == TILE_GROUND){
					reflect = true;

				} else if (Assets.map.collisionMap[(int) ((x+xOffset)/32)][(int) ((y+width-8)/32)] == TILE_SWITCH_A){
					reflect = true;
					Assets.map.collisionMap[(int) (x/32)][(int) ((y+width-8)/32)] = TILE_AIR;
					Assets.map.lowerMap[(int) (x/32)][(int) ((y+width-8)/32)] = 97; // depress switch
					Assets.press.play(1);
					EventHandler.start(EventHandler.WORLD_1_SWITCH_A);

				} else if (Assets.map.collisionMap[(int) ((x+xOffset)/32)][(int) ((y+width-8)/32)] == TILE_SPRING){
					reflect = true;

				} else if (Assets.map.collisionMap[(int) ((x+xOffset)/32)][(int) ((y+width-8)/32)] == TILE_BREAKABLE){

					//TODO: combine this case with the following case in a single method
					reflect = true;
					if (powerup == POWERUP_HEAVY){
						Assets.map.collisionMap[(int) ((x+xOffset)/32)][(int) ((y+width-8)/32)] = 0;
						Assets.map.upperMap[(int) ((x+xOffset)/32)][(int) ((y+width-8)/32)] = 0;
						Assets.map.lowerMap[(int) ((x+xOffset)/32)][(int) ((y+width-8)/32)] = 0;
						particleDirector.add(new Particle(32, 32, (int) (((x+xOffset))/32)*32, (int) ((y+width-8)/32)*32, Particle.TYPE_BREAK));
						Assets.breaks.play(1);
						breakSound = true;
					}

				} 
				if (Assets.map.collisionMap[(int) ((x+xOffset)/32)][(int) ((y+width-40)/32)] == TILE_BREAKABLE){
					reflect = true;
					if (powerup == POWERUP_HEAVY){
						Assets.map.collisionMap[(int) ((x+xOffset)/32)][(int) ((y+width-40)/32)] = 0;
						Assets.map.upperMap[(int) ((x+xOffset)/32)][(int) ((y+width-40)/32)] = 0;
						Assets.map.lowerMap[(int) ((x+xOffset)/32)][(int) ((y+width-40)/32)] = 0;
						particleDirector.add(new Particle(32, 32, (int) (((x+xOffset))/32)*32, (int) ((y+width-40)/32)*32, Particle.TYPE_BREAK));
						if (!breakSound) Assets.breaks.play(1);
					}

				}
				if(reflect){
					reflect(xVel < 0);
				}

			}

			// check for CENTRAL collision 
			facing = xVel < 0 ? -10 : 10;
			if(Assets.map.collisionMap[(int) ((x+width/2+facing)/32)][(int) ((y+8)/32)] == TILE_CARROT){
				Assets.map.collisionMap[(int) ((x+width/2+facing)/32)][(int) ((y+8)/32)] = TILE_AIR;
				Assets.map.lowerMap[(int) ((x+width/2+facing)/32)][(int) ((y+8)/32)] = 0; 
				Assets.chomp.play(1);
				particleDirector.add(new Particle(50, 50, (int) ((x+width/2+facing)/32)*32, (int) ((y+8)/32)*32-16, 1));
			} 

			if(Assets.map.collisionMap[(int) ((x+width/2+facing)/32)][(int) ((y+40)/32)] == TILE_CARROT){
				Assets.map.collisionMap[(int) ((x+width/2+facing)/32)][(int) ((y+40)/32)] = TILE_AIR;
				Assets.map.lowerMap[(int) ((x+width/2+facing)/32)][(int) ((y+40)/32)] = 0; 
				Assets.chomp.play(1);
				particleDirector.add(new Particle(50, 50, (int) ((x+width/2+facing)/32)*32, (int) ((y+40)/32)*32-16, 1));
			}	

			// check for a water collision
			if(powerup != POWERUP_ICE){

				if(!inWater && yVel > 0 && Assets.map.upperMap[(int) ((x+width/2)/32)][(int) ((y+40)/32)] >= TILE_WATER){
					inWater = true;
					Assets.water.play(1);
					particleDirector.add(new Particle(50, 50, (int) x, (int) y+12, Particle.TYPE_SPLASH));

					xVel = xVel/2;
					yVel = yVel/6;
					g = (float) (g/1.5);

				} else if (inWater && yVel < 0 && Assets.map.upperMap[(int) ((x+width/2)/32)][(int) ((y)/32)] < TILE_WATER){
					inWater = false;
					Assets.water.play(1);
					particleDirector.add(new Particle(50, 50, (int) x, (int) y-14, Particle.TYPE_SPLASH));

					xVel = xVel*2;
					g = (float) (g*1.5);
				}

			}

			if(inWater && powerup == POWERUP_FIRE){
				setPowerup(POWERUP_DEFAULT);
				Assets.hiss.play(1);
			}
			
		}
	}



	// reflects the player (to bounce him off a wall, etc)
	public void reflect(boolean left){

		xVel *= -1;
		if(left){
			character.setStrip(0);
			ball.setStrip(ball.stripIndex - 4);
			x++;
		} else {
			character.setStrip(1);
			ball.setStrip(ball.stripIndex + 4);
			x--;
		}
		reflect = false;

	}

	// updates the powerup
	public void setPowerup(int type){
		switch(type){
		case POWERUP_DEFAULT:
			g = 0.5F;
			maxYVel = 12;
			jumpPower = 10;
			if(inWater)	g = (float) (g/1.5);

			if(xVel > 0) {
				ball.setStrip(0);
			} else {
				ball.setStrip(4);
			}
			powerup = POWERUP_DEFAULT;
			break;

		case POWERUP_FEATHER:
			g = 0.4F;
			maxYVel = 6;
			jumpPower = 10;
			if(inWater)	g = (float) (g/1.5);

			if(xVel > 0) {
				ball.setStrip(1);
			} else {
				ball.setStrip(5);
			}
			powerup = POWERUP_FEATHER;
			break;

		case POWERUP_HEAVY:
			g = 1.0F;
			maxYVel = 20;
			jumpPower = 12;
			if(inWater)	g = (float) (g/1.5);

			if(xVel > 0) {
				ball.setStrip(3);
			} else {
				ball.setStrip(7);
			}
			powerup = POWERUP_HEAVY;
			break;

		case POWERUP_ICE:
			g = 0.5F;
			maxYVel = 12;
			jumpPower = 10;
			if(inWater)	g = (float) (g/1.5);

			if(xVel > 0) {
				ball.setStrip(2);
			} else {
				ball.setStrip(6);
			}
			powerup = POWERUP_ICE;
			break;

		case POWERUP_FIRE:
			g = 0.5F;
			maxYVel = 12;
			jumpPower = 8;
			if(inWater)	g = (float) (g/1.5);

			if(xVel > 0) {
				ball.setStrip(2);
			} else {
				ball.setStrip(6);
			}
			powerup = POWERUP_FIRE;
			break;
		}
	}


}

